package org.javanum.number;

/**
 * <p>An immutable implementation of the {@link RealField} interface.</p>
 * 
 * <p>Note that this class extends the {@link Complex} class.</p>
 * 
 * Author: Scott
 * Date: Oct 31, 2009
 *
 */
public final class Real implements RealField<Real,Double>{
	/**
	 * <p>A representation of infinity.</p>
	 */
	public static final Real NaN = new Real(Double.NaN);

    public static final Real POSITIVE_INFINITY =
                        new Real(Double.POSITIVE_INFINITY);

    public static final Real NEGATIVE_INFINITY =
                        new Real(Double.NEGATIVE_INFINITY);

	/**
	 * <p>The multiplicative identity in the real field.</p>
	 */
	@SuppressWarnings({"WeakerAccess"})
    public static final Real ONE = new Real(1);

	/**
	 * <p>The additive identity in the real field.</p>
	 */
	public static final Real ZERO = new Real(0);


    final double value;

    /**
	 * <p>Creates a new instance of this class.</p>
	 * @param value the value of the Real number
	 */
	public Real(double value){
		this.value=value;
	}

	/**
	 * <p>Creates a new instance of this class. This is a 
	 * copy-constructor</p>
	 * @param value the Real number to be copied
	 */
	public Real(Real value){
		this.value=value.value();
	}

    public static Real valueOf(double real){
        return new Real(real);
    }

    public static Real copy(Real real){
        return new Real(real);
    }
	
	@Override
	public Real abs() {
		return new Real(Math.abs(value));
	}
	
	
	public Real add(Real addend) {
		return new Real(this.value()+addend.value());
	}

    private Complex asComplex() {
        return Complex.valueOf(value,0);
    }


    public Real divide(Real divisor) {
		if(divisor.equals(Real.ZERO)) 
			throw new ArithmeticException("Divide by Real.ZERO");
		return new Real(this.value()/divisor.value());
	}

    @Override
    public Real multiplicativeIdentity() {
        return Real.ONE;
    }

    @Override
    public Real multiplicativeInverse() {
        return new Real(1/value);
    }

    @Override
	public boolean equals(Object obj) {
		if(obj==this)return true;
        if(!(obj instanceof Real))return false;

		Real real = (Real)obj;
		return (Double.compare(real.value(), this.value())==0);
	}

	@Override
	public int hashCode() {
		final int prime=31;
		int result=1;
		long temp = Double.doubleToLongBits(value);
		result=prime*result+(int)(temp^(temp >>> 32));
		return result;
	}


	public Real multiply(Real multiplicand) {
		return new Real(value*multiplicand.value);
	}

	public Real subtract(Real subtractand) {
		return new Real(value-subtractand.value);
	}

    @Override
    public Real additiveIdentity() {
        return Real.ZERO;
    }

    @Override
    public Real additiveInverse() {
        return new Real(-value);
    }

    @Override
	public String toString() {
		return value().toString();
	}

	@Override
	public Double value() {
		return value;
	}


    public static boolean isNaN(Real value) {
        return Double.compare(value.value,Double.NaN)==0;
    }

    public static boolean isInfinite(Real value) {
        return Double.isInfinite(value.value);
    }

    public PolarComplex asPolarComplex() {
        return PolarComplex.valueOf(
                Math.abs(value),
                value<0?-Math.PI:0d);
    }
}
